home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2000 / MacHack 2000.toast / pc / The Hacks / Softshoe / Lisa's Mac Parts / Files / Locations / FileLocation.cp < prev    next >
Text File  |  2000-06-23  |  11KB  |  482 lines

  1. // FileLocation.cp
  2.  
  3. #ifndef FileLocation_h
  4. #include "FileLocation.h"
  5. #endif
  6. #ifndef PString_h
  7. #include "PString.h"
  8. #endif
  9. #ifndef Str_h
  10. #include "Str.h"
  11. #endif
  12. #ifndef ProcessInfo_h
  13. #include "ProcessInfo.h"
  14. #endif
  15. #ifndef FileNotFoundError_h
  16. #include "FileNotFoundError.h"
  17. #endif
  18. #ifndef DirectoryNotFoundError_h
  19. #include "DirectoryNotFoundError.h"
  20. #endif
  21. #ifndef DuplicateFileError_h
  22. #include "DuplicateFileError.h"
  23. #endif
  24. #ifndef DirectoryFullError_h
  25. #include "DirectoryFullError.h"
  26. #endif
  27. #ifndef DiskFullError_h
  28. #include "DiskFullError.h"
  29. #endif
  30. #ifndef HardwareVolumeLockError_h
  31. #include "HardwareVolumeLockError.h"
  32. #endif
  33. #ifndef SoftwareVolumeLockError_h
  34. #include "SoftwareVolumeLockError.h"
  35. #endif
  36. #ifndef FileLockError_h
  37. #include "FileLockError.h"
  38. #endif
  39. #ifndef FileBusyError_h
  40. #include "FileBusyError.h"
  41. #endif
  42. #ifndef FilePermissionError_h
  43. #include "FilePermissionError.h"
  44. #endif
  45. #ifndef CatInfo_h
  46. #include "CatInfo.h"
  47. #endif
  48. #ifndef BadFileNameError_h
  49. #include "BadFileNameError.h"
  50. #endif
  51. #ifndef NotAFileError_h
  52. #include "NotAFileError.h"
  53. #endif
  54. #ifndef NotADirectoryError_h
  55. #include "NotADirectoryError.h"
  56. #endif
  57.  
  58. #include <NumberFormatting.h>
  59. #include <StringCompare.h>
  60.  
  61. FileLocation::FileLocation()
  62.   {
  63.     vRefNum = 0;
  64.     parID = 0;
  65.     name[0] = 0;
  66.   }
  67.  
  68. FileLocation::FileLocation( Directory directory,
  69.                                      ConstPString theName )
  70.   {
  71.     name[0] = 0;
  72.     SetParent( directory );
  73.     SetName( theName );
  74.   }
  75.  
  76. FileLocation::FileLocation( Directory directory )
  77.   {
  78.     name[0] = 0;
  79.     CatInfo info( directory );
  80.     *this = info.Location();
  81.   }
  82.  
  83. void FileLocation::Set( Directory directory,
  84.                                 ConstPString theName )
  85.   {
  86.     SetParent( directory );
  87.     SetName( theName );
  88.   }
  89.  
  90. void FileLocation::operator=( Directory directory )
  91.   {
  92.     CatInfo info( directory );
  93.     *this = info.Location();
  94.   }
  95.  
  96. void FileLocation::SetName( ConstPString newName )
  97.   {
  98.     PString( Data( name, sizeof(name) ) ) = newName;
  99.   }
  100.  
  101. void FileLocation::SetName( ConstPString base, uint32 number )
  102.   {
  103.     String31 newName;
  104.     String255 numeral;
  105.     
  106.     NumToString( number, numeral );
  107.     
  108.     if ( base.Length() + numeral.Length() + 1 <= 31 )
  109.       {
  110.         newName.SetLength( base.Length() + numeral.Length() + 1 );
  111.         newName.Head( base.Length() ) << base;
  112.         newName[ base.Length() ] = ' ';
  113.         newName.Tail( base.Length() + 1 ) << numeral;
  114.       }
  115.      else if ( base.Length() + numeral.Length() <= 31 )
  116.       {
  117.         newName.SetLength( base.Length() + numeral.Length() );
  118.         newName.Head( base.Length() ) << base;
  119.         newName.Tail( base.Length() ) << numeral;
  120.       }
  121.      else
  122.       {
  123.         uint32 baseAmount = 31 - numeral.Length() - 1;
  124.         static const uint8 elipsis = 0xc9;
  125.  
  126.         newName.SetLength( 31 );
  127.         newName.Head( baseAmount ) << base;
  128.         newName[ baseAmount ] = elipsis;
  129.         newName.Tail( baseAmount + 1 ) << numeral;
  130.       }
  131.     
  132.     SetName( newName );
  133.   }
  134.  
  135. Directory FileLocation::AsDirectory() const
  136.   {
  137.     return CatInfo( *this ).AsDirectory();
  138.   }
  139.  
  140. bool FileLocation::NameIsValid() const
  141.   {
  142.     ConstPString name( this->name );
  143.     
  144.     if ( name.Length() == 0 )
  145.         return false;
  146.     
  147.     if ( name.Length() > 31 )
  148.         return false;
  149.     
  150.     if ( name[0] == '.' )
  151.         return false;
  152.     
  153.     for ( uint32 i = 0; i < name.Length(); i++ )
  154.         if ( name[i] == ':' )
  155.             return false;
  156.     
  157.     return true;
  158.   }
  159.  
  160. void FileLocation::SetToValidName( ConstPString start )
  161.   {
  162.     SetName( start );
  163.     SetToValidName();
  164.   }
  165.  
  166. void FileLocation::SetToValidName()
  167.   {
  168.     PString name( Data( this->name, sizeof(this->name) ) );
  169.     static const uint8 bullet = 0xA5;
  170.     
  171.     if ( name.Length() == 0 )
  172.       {
  173.         name.SetLength( 1 );
  174.         name[0] = bullet;
  175.       }
  176.     
  177.     if ( name.Length() > 31 )
  178.         name.SetLength( 31 );
  179.     
  180.     if ( name[0] == '.' )
  181.         name[0] = bullet;
  182.     
  183.     for ( uint32 i = 0; i < name.Length(); i++ )
  184.         if ( name[i] == ':' )
  185.             name[i] = '/';
  186.     
  187.     Assert( NameIsValid() );
  188.   }
  189.  
  190. bool operator==( const FileLocation& a, const FileLocation& b )
  191.   {
  192.     return a.vRefNum == b.vRefNum
  193.          && a.parID == b.parID
  194.          && EqualString( a.name, b.name, false, true );
  195.   }
  196.  
  197. void FileLocation::ThrowError( OSErr error )
  198.   {
  199.     if ( error == noErr )
  200.         return;
  201.     
  202.     switch ( error )
  203.       {
  204.         case fnfErr:                throw FileNotFoundError( error );
  205.         case dirNFErr:                throw DirectoryNotFoundError( error );
  206.         case dupFNErr:                throw DuplicateFileError( error );
  207.         case dirFulErr:            throw DirectoryFullError( error );
  208.         case dskFulErr:            throw DiskFullError( error );
  209.         case wPrErr:                throw HardwareVolumeLockError( error );
  210.         case vLckdErr:                throw SoftwareVolumeLockError( error );
  211.         case fLckdErr:                throw FileLockError( error );
  212.         case fBsyErr:                throw FileBusyError( error );
  213.         case afpAccessDenied:    throw FilePermissionError( error );
  214.         case bdNamErr:                throw BadFileNameError( error );
  215.       }
  216.     
  217.     throw FileError( error );
  218.   }
  219.  
  220. bool FileLocation::Exists() const
  221.   {
  222.     Assert( NameIsValid() );
  223.     
  224.     String255 localName( name );
  225.     CInfoPBRec info;
  226.     info.hFileInfo.ioCompletion = 0;
  227.     info.hFileInfo.ioVRefNum = vRefNum;
  228.     info.hFileInfo.ioDirID = parID;
  229.     info.hFileInfo.ioNamePtr = localName;
  230.     info.hFileInfo.ioFVersNum = 0;
  231.     info.hFileInfo.ioFDirIndex = 0;
  232.     
  233.     OSErr error = PBGetCatInfoSync( &info );
  234.     
  235.     if ( error != noErr && error != fnfErr )
  236.         ThrowError( error );
  237.     
  238.     return error == noErr;
  239.   }
  240.  
  241. void FileLocation::FindUnusedName()
  242.   {
  243.     if ( !Exists() )
  244.         return;
  245.         
  246.     String31 baseName( name );
  247.     uint32 number = 1;
  248.     
  249.     do
  250.       {
  251.         Assert( number < maxuint32 );
  252.         SetName( baseName, ++number );
  253.       }
  254.      while ( Exists() );
  255.   }
  256.  
  257. void FileLocation::Up()
  258.   {
  259.     Assert( !IsRoot() );
  260.     if ( IsRoot() )
  261.         ThrowError( dirNFErr );
  262.     
  263.     CatInfo info( Parent() );
  264.     *this = info.Location();
  265.   }
  266.  
  267. void FileLocation::Down( ConstPString child )
  268.   {
  269.     SetParent( AsDirectory() );
  270.     SetName( child );
  271.   }
  272.  
  273. void FileLocation::Sideways( ConstPString sibling )
  274.   {
  275.     SetName( sibling );
  276.   }
  277.  
  278. FileLocation FileLocation::Child( ConstPString child ) const
  279.   {
  280.     return FileLocation( AsDirectory(), child );
  281.   }
  282.  
  283. FileLocation FileLocation::Sibling( ConstPString sibling ) const
  284.   {
  285.     return FileLocation( Parent(), sibling );
  286.   }
  287.  
  288. DirectoryID FileLocation::GetDirectoryID() const
  289.   {
  290.     CatInfo info( *this );
  291.  
  292.     Assert( info.IsDirectory() );
  293.     if ( !info.IsDirectory() )
  294.         ThrowError( afpObjectTypeErr );
  295.  
  296.     return info.Directory().ID();
  297.   }
  298.  
  299. FileID FileLocation::GetFileID() const
  300.   {
  301.     CatInfo info( *this );
  302.     
  303.     Assert( !info.IsDirectory() );
  304.     if ( info.IsDirectory() )
  305.         ThrowError( notAFileErr );
  306.     
  307.     return info.File().ID();
  308.   }
  309.  
  310. void CreateFile( const FileLocation& location,
  311.                       FileType type,
  312.                       FileSignature signature,
  313.                       ScriptID script )
  314.   {
  315.     Assert( location.NameIsValid() );
  316.      FileLocation::ThrowError( FSpCreate( &location,
  317.                                                       signature.Signature(),
  318.                                                       type.Type(),
  319.                                                       script.ID() ) );
  320.   }
  321.  
  322. void CreateFile( const FileLocation& location,
  323.                       FileType type,
  324.                       ScriptID script )
  325.   {
  326.     CreateFile( location,
  327.                     type,
  328.                     ProcessInfo::Application().Signature(),
  329.                     script );
  330.   }
  331.  
  332. Directory CreateDirectory( const FileLocation& location, ScriptID script )
  333.   {
  334.     Assert( location.NameIsValid() );
  335.     int32 directory;
  336.      FileLocation::ThrowError( FSpDirCreate( &location, script.ID(), &directory ) );
  337.      return Directory( location.Volume(), DirectoryID( directory ) );
  338.   }
  339.  
  340. void DeleteFile( const FileLocation& file )
  341.   {
  342.     Assert( file.NameIsValid() );
  343.     DeleteFile( CatInfo( file ) );
  344.   }
  345.  
  346. void DeleteDirectory( const FileLocation& directory )
  347.   {
  348.     Assert( directory.NameIsValid() );
  349.     DeleteDirectory( CatInfo( directory ) );
  350.   }
  351.  
  352. void LockFile( const FileLocation& file )
  353.   {
  354.     Assert( file.NameIsValid() );
  355.      FileLocation::ThrowError( FSpSetFLock( &file ) );
  356.   }
  357.  
  358. void UnlockFile( const FileLocation& file )
  359.   {
  360.     Assert( file.NameIsValid() );
  361.      FileLocation::ThrowError( FSpRstFLock( &file ) );
  362.   }
  363.  
  364. void MoveFile( const FileLocation& source, const FileLocation& destination )
  365.   {
  366.     Assert( source.Volume() == destination.Volume() );
  367.     Assert( source != destination );
  368.     Assert( source.NameIsValid() );
  369.     Assert( destination.NameIsValid() );
  370.  
  371.     MoveFile( CatInfo( source ), destination );
  372.   }
  373.  
  374. void SwapFiles( const FileLocation& left, const FileLocation& right )
  375.   {
  376.     Assert( left.Volume() == right.Volume() );
  377.     Assert( left != right );
  378.     Assert( left.NameIsValid() );
  379.     Assert( right.NameIsValid() );
  380.     
  381.      FileLocation::ThrowError( FSpExchangeFiles( &left, &right ) );
  382.   }
  383.  
  384. void DeleteDirectory( const CatInfo& source )
  385.   {
  386.     if ( !source.IsDirectory() )
  387.         throw NotADirectoryError( afpObjectTypeErr );
  388.  
  389.      FileLocation::ThrowError( FSpDelete( &source.Location() ) );
  390.   }
  391.  
  392. void DeleteFile( const CatInfo& source )
  393.   {
  394.     if ( !source.IsFile() )
  395.         throw NotAFileError( notAFileErr );
  396.  
  397.      FileLocation::ThrowError( FSpDelete( &source.Location() ) );
  398.   }
  399.  
  400. void MoveFile( const CatInfo& source, const FileLocation& destination )
  401.   {
  402.     Assert( source.Location().Volume() == destination.Volume() );
  403.     Assert( source.Location() != destination );
  404.     Assert( source.Location().NameIsValid() );
  405.     Assert( destination.NameIsValid() );
  406.  
  407.     if ( !source.IsFile() )
  408.         throw NotAFileError( notAFileErr );
  409.     
  410.     if ( destination.ParentID() == source.Location().ParentID() )
  411.          FileLocation::ThrowError( FSpRename( &source.Location(), destination.Name() ) );
  412.      else
  413.          FileLocation::ThrowError( FSpCatMove( &source.Location(), &destination ) );
  414.   }
  415.  
  416.  
  417. void ForceDirectoryExistence( const FileLocation& destination )
  418.   {
  419.     CatInfo info;
  420.     bool exists = info.TryToGet( destination );
  421.     
  422.     if ( exists && info.IsDirectory() )
  423.         return;
  424.     
  425.     if ( exists )
  426.         ForceNonexistence( destination );
  427.     
  428.     CreateDirectory( destination );
  429.   }
  430.  
  431. void ForceNonexistence( const FileLocation& source )
  432.   {
  433.     Assert( source.NameIsValid() );
  434.     
  435.     OSErr error = FSpDelete( &source );
  436.  
  437.     if ( error != noErr && error != fnfErr )
  438.          FileLocation::ThrowError( error );
  439.   }
  440.  
  441. void ForceMoveFile( const FileLocation& source, const FileLocation& destination )
  442.   {
  443.     CatInfo sourceInfo( source );
  444.  
  445.     // Check for these errors before deleting:
  446.         if ( !sourceInfo.IsFile() )
  447.             throw NotAFileError( notAFileErr );
  448.  
  449.     ForceNonexistence( destination );
  450.     MoveFile( sourceInfo, destination );
  451.   }
  452.  
  453. void ForceCopyFile( const FileLocation& source, const FileLocation& destination )
  454.   {
  455.     CatInfo sourceInfo( source );
  456.  
  457.     // Check for these errors before deleting:
  458.         if ( !sourceInfo.IsFile() )
  459.             throw NotAFileError( notAFileErr );
  460.  
  461.     ForceNonexistence( destination );
  462.     CopyFile( sourceInfo, destination );
  463.   }
  464.  
  465. void DeleteRecursively( const FileLocation& top )
  466.   {
  467.     CatInfo info( top );
  468.     
  469.     while ( true )
  470.       {
  471.         while ( info.IsDirectory() && info.TryToGet( info.AsDirectory(), 1 ) )
  472.             ;
  473.     
  474.          FileLocation::ThrowError( FSpDelete( &info.Location() ) );
  475.      
  476.          if ( info.Location() == top )
  477.              return;
  478.      
  479.          info.Up();
  480.       }
  481.   }
  482.